#pragma once
#include <iostream>
#include <vector>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>

using namespace std;

template <typename T>
class RingQueue{
public:
    RingQueue( int max_size = 10)
    : max_size_(max_size)
    ,tail_(0)
    ,head_(0)
    ,queue_(max_size)
    {
        sem_init(&p_space_sem_, 0, max_size);
        sem_init(&c_data_sem_, 0, 0);
        pthread_mutex_init(&p_mutex_, NULL);
        pthread_mutex_init(&c_mutex_, NULL);
    }
    ~RingQueue(){
        sem_destroy(&p_space_sem_);
        sem_destroy(&c_data_sem_);
        pthread_mutex_destroy(&p_mutex_);
        pthread_mutex_destroy(&c_mutex_);
    }

    void Push(T& data) {
        sem_wait( &p_space_sem_);   // P操作,只有p_space_sem_ 大于0才可执行，执行后 p_space_sem_ 减1
                                    // 当生产者生产满了，p_space_sem_就会为0，然后停止生产，等待消费者消费
        pthread_mutex_lock(&p_mutex_);
        queue_[head_] = data;
        head_ = (head_ + 1) % max_size_; // 必须更新头指针
        pthread_mutex_unlock(&p_mutex_);

        sem_post( &c_data_sem_);    // V操作 
    }

    T Pop(){
        sem_wait( &c_data_sem_);    // P操作

        pthread_mutex_lock(&c_mutex_);
        T  data = queue_[tail_];
        tail_ = (tail_ + 1) % max_size_;
        pthread_mutex_unlock(&c_mutex_);

        sem_post( &p_space_sem_);   // V操作
        return data;
    }


private:
    int max_size_;
    int tail_;
    int head_; // 指向生产者欲生产的区域
    vector<T> queue_;   
    sem_t c_data_sem_;
    sem_t p_space_sem_;
    pthread_mutex_t  c_mutex_;
    pthread_mutex_t  p_mutex_;
};
